package cn.bubi.access.utils;

import java.util.HashMap;
import java.util.Map;

public class PrimitiveUtils{

    private static Map<Class<?>, Converter> converters = new HashMap<>();

    static{
        converters.put(Boolean.class, new BooleanConverter());
        converters.put(boolean.class, new BooleanValueConverter());
        converters.put(Byte.class, new ByteConverter());
        converters.put(byte.class, new ByteValueConverter());
        converters.put(Character.class, new CharConverter());
        converters.put(char.class, new CharValueConverter());
        converters.put(Integer.class, new IntegerConverter());
        converters.put(int.class, new IntegerValueConverter());
        converters.put(Long.class, new LongConverter());
        converters.put(long.class, new LongValueConverter());
        converters.put(Double.class, new DoubleConverter());
        converters.put(double.class, new DoubleValueConverter());
        converters.put(Float.class, new FloatConverter());
        converters.put(float.class, new FloatValueConverter());
    }

    /**
     * 判断指定的两个类型是否互为包装类；
     *
     * @param type1
     * @param type2
     * @return
     */
    public static boolean isWrapping(Class<?> type1, Class<?> type2){
        Converter converter = converters.get(type1);
        return converter != null && converter.isWrapping(type2);
    }

    /**
     * 判断指定的类型是否是基本类型或者基本类型的包装类；
     *
     * @param clazz
     * @return
     */
    public static boolean isPrimitiveType(Class<?> clazz){
        return converters.containsKey(clazz);
    }

    /**
     * 返回指定类型的默认值；
     * <p>
     * 如果指定类型是原生类型，则返回默认的原始类型的值；否则，返回 null；
     *
     * @param clazz
     * @return
     */
    public static Object getDefaultValue(Class<?> clazz){
        Converter converter = converters.get(clazz);
        if (converter == null) {
            return null;
        }
        return converter.defaultValue();
    }

    /**
     * 将指定的数据转为指定的类型；<br>
     * <p>
     * 如果指定的类型不是基本类型，则总是返回 null；
     *
     * @param data
     * @param clazz
     * @return
     */
    public static <T> T castTo(Object data, Class<T> clazz){
        Converter converter = converters.get(clazz);
        if (converter == null) {
            return null;
        }
        return (T) converter.convert(data);
    }

    private static interface Converter{

        Object defaultValue();

        Object convert(Object data);

        boolean isWrapping(Class<?> type);

    }

    private static class BooleanConverter implements Converter{

        @Override
        public Object convert(Object data){
            if (data == null) {
                return null;
            }
            if (data instanceof Boolean) {
                return (Boolean) data;
            }
            return Boolean.parseBoolean(data.toString());
        }

        @Override
        public Object defaultValue(){
            return null;
        }

        @Override
        public boolean isWrapping(Class<?> type){
            return type == boolean.class || type == Boolean.class;
        }
    }

    private static class BooleanValueConverter extends BooleanConverter{

        @Override
        public Object convert(Object data){
            Boolean value = (Boolean) super.convert(data);
            if (value == null) {
                return false;
            }
            return value;
        }

        @Override
        public Object defaultValue(){
            return false;
        }
    }

    private static class CharConverter implements Converter{

        @Override
        public Object convert(Object data){
            if (data == null) {
                return null;
            }
            if (data instanceof Character) {
                return (char) ((Character) data).charValue();
            }
            if (data instanceof Byte) {
                return (char) ((Byte) data).byteValue();
            }
            if (data instanceof String) {
                String str = (String) data;
                if (str.length() == 1) {
                    return str.charAt(0);
                }
            }
            throw new IllegalArgumentException("Cann't conver [" + data + "] to charater!");
        }

        @Override
        public Object defaultValue(){
            return null;
        }

        @Override
        public boolean isWrapping(Class<?> type){
            return type == char.class || type == Character.class;
        }
    }

    private static class CharValueConverter extends CharConverter{

        @Override
        public Object convert(Object data){
            Character value = (Character) super.convert(data);
            if (value == null) {
                throw new IllegalArgumentException("Cann't convert null charater to char!");
            }
            return value;
        }

        @Override
        public Object defaultValue(){
            return (char) 0;
        }
    }

    private static class ByteConverter implements Converter{

        @Override
        public Object convert(Object data){
            if (data == null) {
                return null;
            }
            if (data instanceof Byte) {
                return (int) ((Byte) data).byteValue();
            }
            return Byte.parseByte(data.toString());
        }

        @Override
        public Object defaultValue(){
            return null;
        }

        @Override
        public boolean isWrapping(Class<?> type){
            return type == byte.class || type == Byte.class;
        }
    }

    private static class ByteValueConverter extends ByteConverter{

        @Override
        public Object convert(Object data){
            Byte value = (Byte) super.convert(data);
            if (value == null) {
                return Byte.valueOf((byte) 0);
            }
            return value;
        }

        @Override
        public Object defaultValue(){
            return (byte) 0;
        }
    }

    private static class IntegerConverter implements Converter{

        @Override
        public Object convert(Object data){
            if (data == null) {
                return null;
            }
            if (data instanceof Integer) {
                return (Integer) data;
            }
            if (data instanceof Byte) {
                return ((Byte) data).intValue();
            }
            return Integer.parseInt(data.toString());
        }

        @Override
        public Object defaultValue(){
            return null;
        }

        @Override
        public boolean isWrapping(Class<?> type){
            return type == int.class || type == Integer.class;
        }
    }

    private static class IntegerValueConverter extends IntegerConverter{

        @Override
        public Object convert(Object data){
            Integer value = (Integer) super.convert(data);
            if (value == null) {
                return 0;
            }
            return value;
        }

        @Override
        public Object defaultValue(){
            return (int) 0;
        }
    }

    private static class LongConverter implements Converter{

        @Override
        public Object convert(Object data){
            if (data == null) {
                return null;
            }
            if (data instanceof Long) {
                return (Long) data;
            }
            if (data instanceof Integer) {
                return ((Integer) data).longValue();
            }
            if (data instanceof Byte) {
                return ((Byte) data).longValue();
            }
            return Long.parseLong(data.toString());
        }

        @Override
        public Object defaultValue(){
            return null;
        }

        @Override
        public boolean isWrapping(Class<?> type){
            return type == long.class || type == Long.class;
        }
    }

    private static class LongValueConverter extends LongConverter{

        @Override
        public Object convert(Object data){
            Long value = (Long) super.convert(data);
            if (value == null) {
                return Long.valueOf(0);
            }
            return value;
        }

        @Override
        public Object defaultValue(){
            return 0L;
        }
    }

    private static class DoubleConverter implements Converter{

        @Override
        public Object convert(Object data){
            if (data == null) {
                return null;
            }
            if (data instanceof Double) {
                return (Double) data;
            }
            if (data instanceof Float) {
                return ((Float) data).doubleValue();
            }
            if (data instanceof Long) {
                return ((Long) data).doubleValue();
            }
            if (data instanceof Integer) {
                return ((Integer) data).doubleValue();
            }
            if (data instanceof Byte) {
                return ((Byte) data).doubleValue();
            }
            return Double.parseDouble(data.toString());
        }

        @Override
        public Object defaultValue(){
            return null;
        }

        @Override
        public boolean isWrapping(Class<?> type){
            return type == double.class || type == Double.class;
        }
    }

    private static class DoubleValueConverter extends DoubleConverter{

        @Override
        public Object convert(Object data){
            Long value = (Long) super.convert(data);
            if (value == null) {
                return Long.valueOf(0);
            }
            return value;
        }

        @Override
        public Object defaultValue(){
            return (double) 0;
        }
    }

    private static class FloatConverter implements Converter{

        @Override
        public Object convert(Object data){
            if (data == null) {
                return null;
            }
            if (data instanceof Float) {
                return (Float) data;
            }
            if (data instanceof Long) {
                return ((Long) data).floatValue();
            }
            if (data instanceof Integer) {
                return ((Integer) data).floatValue();
            }
            if (data instanceof Byte) {
                return ((Byte) data).floatValue();
            }
            return Float.parseFloat(data.toString());
        }

        @Override
        public Object defaultValue(){
            return null;
        }

        @Override
        public boolean isWrapping(Class<?> type){
            return type == float.class || type == Float.class;
        }
    }

    private static class FloatValueConverter extends FloatConverter{
        private static final Float DEFAULT_FLOAT = Float.valueOf(0);

        @Override
        public Object convert(Object data){
            Float value = (Float) super.convert(data);
            if (value == null) {
                return DEFAULT_FLOAT;
            }
            return value;
        }

        @Override
        public Object defaultValue(){
            return (float) 0;
        }
    }
}
